package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author atguigu-mqx
 * @ClassName TestServiceImpl
 * @description: TODO
 * @date 2023年11月04日
 * @version: 1.0
 */
@Service
public class TestServiceImpl implements TestService {

    /*
    1.  先在缓存中初始化一个num = 0 的key
    2.  从缓存中获取num 数据
        true:
            则将数据+1 , 再写回缓存
        false:
            return;
     */

    @Autowired
    private StringRedisTemplate redisTemplate;

//    @Override
//    public void testLock() {
//
//    }
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void testLock() {
        //  上锁：
        RLock lock = redissonClient.getLock("lock");
        //  没有设置过期时间 -- 宠物
        lock.lock();
        //  这个锁10秒之后就会失效
        lock.lock(10,TimeUnit.SECONDS);
        boolean res = false;
        try {
            res = lock.tryLock(1, 10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //  获取到锁
        if (res){
            try {
                //  执行业务逻辑
                //  获取num 数据
                String num = redisTemplate.opsForValue().get("num");
                //  判断
                if (StringUtils.isEmpty(num)){
                    return;
                }
                //  进行数据类型转换：
                int numValue = Integer.parseInt(num);
                //  将num 进行+1。再写回缓存！ 先计算，再赋值.
                redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
            } catch (NumberFormatException e) {
                throw new RuntimeException(e);
            } finally {
                //  解锁
                lock.unlock();
            }
        }
    }


    /*@Override
    public void testLock() {
        //  执行setnx 命令 setnx key value;
        //  Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", "atguigu");
        //  执行 set key value nx ex timeout;  timeout: 应该根据实际业务执行的时间填写！
        String token = UUID.randomUUID().toString();

        Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", token,3,TimeUnit.SECONDS);
        //  判断
        if (result){
            //  result = true; 表示这个线程获取到资源，上锁成功！
            //  获取num 数据
            String num = redisTemplate.opsForValue().get("num");
            //  判断
            if (StringUtils.isEmpty(num)){
                return;
            }

            //            try {
            //                Thread.sleep(1000);
            //            } catch (InterruptedException e) {
            //                throw new RuntimeException(e);
            //            }
            ////            this.redisTemplate.expire("lock",5, TimeUnit.MINUTES);
            //            //  创建线程
            //            Thread t1 = new Thread(()->{
            //                //  获取锁的过期时间
            //                Long expireTime = redisTemplate.getExpire("lock");
            //                //  剩余时间
            //                if (expireTime==2){
            //                    System.out.println("续期....");
            //                    //  续期
            //                    redisTemplate.expire("lock",2,TimeUnit.SECONDS);
            //                }
            //            });
            //            //  设置守护线程.
            //            t1.setDaemon(true);
            //            //  启动线程.
            //            t1.start();
            //  进行数据类型转换：
            int numValue = Integer.parseInt(num);

            //  将num 进行+1。再写回缓存！ 先计算，再赋值.
            redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
            //  是否锁资源
            //            if (token.equals(this.redisTemplate.opsForValue().get("lock"))){
            //                //  删除锁。 index1- index2
            //                this.redisTemplate.delete("lock");
            //            }

            //  定义lua脚本 lock(); unlock();
            String scriptText = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                    "then\n" +
                    "    return redis.call(\"del\",KEYS[1])\n" +
                    "else\n" +
                    "    return 0\n" +
                    "end";
            //  执行lua脚本：
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
            //  赋值lua脚本：
            redisScript.setScriptText(scriptText);
            redisScript.setResultType(Long.class);
            this.redisTemplate.execute(redisScript, Arrays.asList("lock"),token);

        } else {
            try {
                //  没有获取到锁.
                Thread.sleep(300);
                testLock();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }*/


}
